package preprocessing;

//import java.util.Vector;
//
//import datastructures.RegionParameters;
//import datastructures.UserParameters;


public class EpidemiologyConstraintHandler {
//
//	private final UserParameters userParams;
//	private final WindowingSystem windowMaker;
//	private final int[][] significanceList;
//	
//	private int[] k_min;
//	private int[] k_max;
//	
//	private final CaseMatrix pMatrix;
//	
//	private int trialIncrement, numberOfTrialSlices; 
//	private SearchAreaCalculator[] currentPowerAreaSlices = null;
//	private SearchAreaCalculator previouslyScannedArea = null;
//	
//	/*
//	 * Constructor initializes the interaction frequencies.
//	 */
//	public EpidemiologyConstraintHandler ( UserParameters userparams, int[][] significances ) throws Exception 
//	{	
//		userParams = userparams;
//		significanceList = significances;
//		windowMaker = new WindowingSystem(userParams);
//		
//		trialIncrement = userparams.getTrialIncrement();
//		numberOfTrialSlices = userparams.getNumberOfTrialSlices();
//		currentPowerAreaSlices = new SearchAreaCalculator[numberOfTrialSlices];
//		
//		//1. Make a frequency grid	
//		System.out.println("\nMaking frequency hypergrid ... \n");	
//		FrequencyCalculator frequencyGrid = new FrequencyCalculator ( userParams, windowMaker );
//		frequencyGrid.compute ( MatrixOperations.calculateFrequency, new CaseMatrix(windowMaker, userParams.getMaxorder()),  true );
//		
//		
//		//2. Screen out coordinates that are too common from the grid.
//		System.out.println("\nExcluding the following coordinates due to insufficient rareness ... \n");
//		CaseMatrix maxPermissibleCooccurence = new CaseMatrix(windowMaker, userparams.getMaxorder(), userparams.getCooccurrence());
//		CaseMatrix relevantCoordinates = frequencyGrid.compute( MatrixOperations.lessThan, maxPermissibleCooccurence, false);
//		relevantCoordinates.compute(MatrixOperations.notEqZeroMask, null, true);
//		
//		
//		//3. Calculate expected Cases and expected Controls given the expected Penetrance
//		System.out.println("\nCalculating expected Controls and Cases for various allelic combinations ... \n");	
//		
//		ExpectedControlsCalculator expectedControls = new ExpectedControlsCalculator ( userParams, windowMaker );
//		expectedControls.compute (MatrixOperations.calculateExpectedControls, frequencyGrid,  true );
//		expectedControls.compute(MatrixOperations.matrixMultiply, relevantCoordinates, true);
//		
//		ExpectedCasesCalculator expectedCases = new ExpectedCasesCalculator ( userParams, windowMaker );
//		expectedCases.compute (MatrixOperations.calculateExpectedCases, frequencyGrid,  true );
//		expectedCases.compute(MatrixOperations.matrixMultiply, relevantCoordinates, true);
//
//		
//		//4. Calculate number of cases needed against expected Controls for significance
//		System.out.println("\nCalculating needed Cases for significance ... \n");
//		NeededCaseCalculator neededCases = new NeededCaseCalculator ( userParams, windowMaker, significanceList );
//		neededCases.compute ( MatrixOperations.calculateNeededCases, expectedControls, true );
//		neededCases.compute( MatrixOperations.matrixMultiply, relevantCoordinates, true );
//		
//		
//		//5. Calculate max possible cases given disease prevalence, and subsequently, max possible carriers given penetrance of multi-locus genotype
//		System.out.println("\nCalculating allelic combinations with enough penetrance (lower bound) to make significance ... \n");		
//		
//		MaxCaseCalculator maxCases = new MaxCaseCalculator ( userParams, windowMaker );	
//		maxCases.compute ( MatrixOperations.calculateMaxCases, frequencyGrid,  true );
//		maxCases.compute( MatrixOperations.matrixMultiply, relevantCoordinates, true );
//		
//		PenetranceCalculator penetrantCases = new PenetranceCalculator( userParams, windowMaker);
//		penetrantCases.compute( MatrixOperations.calculatePenetrantCases, maxCases, true );
//		penetrantCases.compute( MatrixOperations.matrixMultiply, relevantCoordinates, true );
//		
//		
//		//6. Find coordinates which are significant, penetrant and sufficiently rare.
//		System.out.println("\nCalculating allelic combinations with sufficient penetrance (upper bound) to make significance ... \n");	
//		CaseMatrix significantRarePenetrantCoordinates = penetrantCases.compute (MatrixOperations.greaterThan, neededCases, false); //only gets the = penetrance
//		
//		CaseMatrix otherPossibleCoordinates = neededCases.compute (MatrixOperations.lessThan, maxCases, false);
//		CaseMatrix coordinatesIfAllowGreaterPenetrance = otherPossibleCoordinates.compute (MatrixOperations.greaterThan, significantRarePenetrantCoordinates, false);
//		
//		significantRarePenetrantCoordinates.compute(MatrixOperations.Union, coordinatesIfAllowGreaterPenetrance, true); //now we have all combos with >= penetrance
//		significantRarePenetrantCoordinates.compute( MatrixOperations.matrixMultiply, relevantCoordinates, true);
//		
//		
//		//7. Filter out coordinates with too many contributing SNPs showing marginal effects
//		System.out.println("\nExcluding the following combinations because more than " + userParams.getMarginals() + " SNPs will have marginal effects ... \n");
//		
//		MarginalEffectsCalculator marginalEffects = new MarginalEffectsCalculator( userParams, windowMaker, expectedControls, expectedCases, significanceList );
//		marginalEffects.compute ( MatrixOperations.calculateMarginalEffects, significantRarePenetrantCoordinates, true );
//		
//		CaseMatrix maxMarginalsPermittedMatrix = new CaseMatrix(windowMaker, userparams.getMaxorder()+1, userparams.getMarginals());
//		CaseMatrix significantRarePenetrantCoordinatesWithoutMarginals = marginalEffects.compute(MatrixOperations.lessThan, maxMarginalsPermittedMatrix, false);
//		significantRarePenetrantCoordinatesWithoutMarginals.compute( MatrixOperations.matrixMultiply, relevantCoordinates, true);
//		
//		
//		//8. Calculate the probability matrix from the remaining coordinates.
//		System.out.println("\nCalculating probability matrix with remaining combinations ... \n");
//		
//		CaseMatrix mask = significantRarePenetrantCoordinatesWithoutMarginals.compute(MatrixOperations.notEqZeroMask, null, false);
//		CaseMatrix residuals = significantRarePenetrantCoordinates.compute( MatrixOperations.matrixMultiply, mask, false );
//		
//		double denominator = (double) 1 / (double) userParams.getNumber_of_cases();
//		pMatrix = residuals.compute( MatrixOperations.matrixMultiply, (new CaseMatrix(windowMaker, userparams.getMaxorder(), denominator)), false );
//		
//		
//		//9. Build bounds on filter strength
//		System.out.println("\nAssigning filters to regions of search space based on required power ... \n");
//		buildKBounds ( userparams.getMaxorder() );
//		
//	}
//
//	
//	
//
//	public Vector<RegionParameters> findUniqueSearchCoordinates ( int filter_strength ) 
//	{
//		//Calculate power's for various slices of T first
//		int slice = 0; 
//		for ( int trials = trialIncrement; trials<=numberOfTrialSlices*trialIncrement; trials += trialIncrement ) {				
//			currentPowerAreaSlices[slice] = new SearchAreaCalculator (userParams, windowMaker, filter_strength, trials);
//			currentPowerAreaSlices[slice].compute ( MatrixOperations.calculateSearchArea, pMatrix, true );
//			slice++;
//		}		
//		
//		//Now aggregate what you've seen
//		Vector<RegionParameters> regionForThisFilter = new Vector<RegionParameters>();
//		for (slice = 0; slice < numberOfTrialSlices; slice++ ) {
//			
//			//stuff that hasn't been seen before
//			CaseMatrix applicableSearchArea = currentPowerAreaSlices[slice].compute ( MatrixOperations.Exclusive, previouslyScannedArea, false );
//		
//			//now, we have seen it. update.
//			if( previouslyScannedArea != null)
//				previouslyScannedArea.compute( MatrixOperations.Union, currentPowerAreaSlices[slice], true );
//			else {
//				previouslyScannedArea = currentPowerAreaSlices [slice]; //last slice
//			}	
//			
//			//what are the coordinates?
//			Vector<int[]> searchCoordinates = applicableSearchArea.getNonZeroCoordinates ( userParams.getMaxorder() );
//			for(int[] entry : searchCoordinates) 
//				regionForThisFilter.add( new RegionParameters(filter_strength, (1+slice)*trialIncrement, entry) );
//			
//		}
//		
//		if ( regionForThisFilter.size() != 0 )
//			return regionForThisFilter;
//		
//		return null;
//	}
//	
//
//	private void buildKBounds ( int maxOrder ) {
//
//		k_min = new int [maxOrder];
//		k_max = new int [maxOrder];		
//		
//		for(int order=0; order<maxOrder; order++) {
//			double maxp = 0;
//			double minp=0;
//			
//			switch(order+1){
//				
//			case 1:
//
//					double[] pmatrix1d = pMatrix.getMatrix1D();
//					for(int i=0; i<pmatrix1d.length; i++)
//						if(maxp < pmatrix1d[i] )
//							maxp = Math.min(pmatrix1d[i], 0.9999999);
//					
//					minp = maxp;
//					for(int i=0; i<pmatrix1d.length; i++)
//						if(minp > pmatrix1d[i] && pmatrix1d[i]!=0 )
//							minp = pmatrix1d[i];
//					
//					k_max[order] = (int) Math.min( Math.floor( Math.log(userParams.getP_lowest()) / Math.log( maxp ) ), 40);
//					k_min[order] = (int) Math.floor( Math.log(userParams.getP_lowest()) / Math.log( minp ) ); // Math.log( (double) significanceList[order][0] / (double) userParams.getNumber_of_cases() ) ); // p^k > p_threshold
//					break;
//	
//				case 2:
//					double[][] pmatrix2d = pMatrix.getMatrix2D();
//					for(int i=0; i<pmatrix2d.length; i++)
//						for(int j=i; j<pmatrix2d[i].length; j++)
//						if(maxp < pmatrix2d[i][j] )
//							maxp = Math.min(pmatrix2d[i][j], 0.9999999);
//					
//					minp = maxp;
//					for(int i=0; i<pmatrix2d.length; i++)
//						for(int j=i; j<pmatrix2d[i].length; j++)
//							if(minp > pmatrix2d[i][j] && pmatrix2d[i][j]!=0 )
//								minp = pmatrix2d[i][j];
//					
//					k_max[order] = (int) Math.min( Math.floor( Math.log(userParams.getP_lowest()) / Math.log( maxp ) ), 40);
//					k_min[order] = (int) Math.floor( Math.log(userParams.getP_lowest()) / Math.log( minp ) ); //Math.log( (double) significanceList[order][0] / (double) userParams.getNumber_of_cases() ) );
//					break;
//	
//				case 3:
//					double[][][] pmatrix3d = pMatrix.getMatrix3D();
//					for(int i=0; i<pmatrix3d.length; i++)
//						for(int j=i; j<pmatrix3d[i].length; j++)
//							for(int k=j; k<pmatrix3d[i][j].length; k++)
//								if(maxp < pmatrix3d[i][j][k] )
//									maxp = Math.min(pmatrix3d[i][j][k], 0.9999999);
//					
//					minp = maxp;
//					for(int i=0; i<pmatrix3d.length; i++)
//						for(int j=i; j<pmatrix3d[i].length; j++)
//							for(int k=j; k<pmatrix3d[i][j].length; k++)
//								if ( minp > pmatrix3d[i][j][k] && pmatrix3d[i][j][k]!=0 )
//									minp = pmatrix3d[i][j][k];
//					
//					
//					k_max[order] = (int) Math.min( Math.floor( Math.log(userParams.getP_lowest()) / Math.log( maxp ) ), 40);
//					k_min[order] = (int) Math.floor( Math.log(userParams.getP_lowest()) / Math.log( minp ) ); //Math.log( (double) significanceList[order][0] / (double) userParams.getNumber_of_cases() ) );
//					break;
//	
//				default: //k=4
//					double[][][][] pmatrix4d = pMatrix.getMatrix4D();
//					for(int i=0; i<pmatrix4d.length; i++)
//						for(int j=i; j<pmatrix4d[i].length; j++)
//							for(int k=j; k<pmatrix4d[i][j].length; k++)
//								for(int m=k; m<pmatrix4d[i][j][k].length; m++)	
//									if(maxp < pmatrix4d[i][j][k][m] )
//										maxp = Math.min(pmatrix4d[i][j][k][m], 0.9999999);
//					
//					minp = maxp;
//					for(int i=0; i<pmatrix4d.length; i++)
//						for(int j=i; j<pmatrix4d[i].length; j++)
//							for(int k=j; k<pmatrix4d[i][j].length; k++)
//								for(int m=k; m<pmatrix4d[i][j][k].length; m++)	
//									if (minp > pmatrix4d[i][j][k][m] && pmatrix4d[i][j][k][m]!=0 )
//										minp = pmatrix4d[i][j][k][m];
//					
//					k_max[order] = (int) Math.min( Math.floor( Math.log( userParams.getP_lowest()) / Math.log( maxp ) ), 40);
//					k_min[order] = (int) Math.floor( Math.log( userParams.getP_lowest()) /  Math.log( minp ) ); //Math.log( (double) significanceList[order][0] / (double) userParams.getNumber_of_cases() ) );
//					break;
//			}	
//
//			System.out.println("kmax " + (order+1) + " = " + k_max[order] + "\t kmin " + (order+1) + " = " + k_min[order]);
//		}	
//
//	}
//	
//	public int getKmin ( ) {
//		int min = 40;
//		for(int i=0; i< k_min.length; i++)
//			if (k_min[i] < min)
//				min = k_min[i];
//		return min;
//	}
//
//	public int getKmax( ) {
//		int max = 0;
//		for(int i=0; i< k_max.length; i++)
//			if (k_max[i] > max)
//				max = k_max[i];
//		return max;
//	}

}
